import Axios, {
  AxiosInstance,
  AxiosRequestConfig,
  CustomParamsSerializer,
} from "axios";
import {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig,
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
import { getToken, formatToken, removeToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import { router, resetRouter } from "@/router";
import { message } from "@/utils/message";
import { ElNotification } from "element-plus";
// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 30000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json", //'multipart/form-data','application/x-www-form-urlencoded'
    "X-Requested-With": "XMLHttpRequest",
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer,
  },
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** token过期后，暂存待执行的请求 */
  private static requests = [];

  /** 防止重复刷新token */
  private static isRefreshing = false;

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {
    //拦截请求做一些参数修改
    beforeRequestCallback: (config) => {},
  };

  /** 保存当前Axios实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 重连原始请求 */
  private static retryOriginalRequest(config: PureHttpRequestConfig) {
    return new Promise((resolve) => {
      PureHttp.requests.push((token: string) => {
        config.headers["Authorization"] = formatToken(token);
        resolve(config);
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 开启进度条动画
        NProgress.start();
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }
        return config;

        /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
        const whiteList = ["/refreshToken", "/login"];
        return whiteList.some((v) => config.url.indexOf(v) > -1)
          ? config
          : new Promise((resolve) => {
              const data = getToken();
              if (data) {
                const now = new Date().getTime();
                const expired = parseInt(data.expires) - now <= 0;
                if (expired) {
                  if (!PureHttp.isRefreshing) {
                    PureHttp.isRefreshing = true;
                    // token过期刷新
                    useUserStoreHook()
                      .handRefreshToken({ refreshToken: data.refreshToken })
                      .then((res) => {
                        const token = res.data.accessToken;
                        config.headers["Authorization"] = formatToken(token);
                        PureHttp.requests.forEach((cb) => cb(token));
                        PureHttp.requests = [];
                      })
                      .finally(() => {
                        PureHttp.isRefreshing = false;
                      });
                  }
                  resolve(PureHttp.retryOriginalRequest(config));
                } else {
                  config.headers["Authorization"] = formatToken(
                    data.accessToken
                  );
                  resolve(config);
                }
              } else {
                resolve(config);
              }
            });
      },
      (error) => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        // 特殊处理：如果返回的是 JSON 字符串，需要先解析
        // 判断是否为维度配置元数据接口
        const isMetadataApi = response.config?.url?.includes(
          "/api/risk/dimension/config_metadata"
        );

        if (isMetadataApi && typeof response.data === "string") {
          try {
            // 处理 JSON 字符串中的特殊值（Infinity, NaN, undefined）
            // 将这些值替换为 null 或字符串，使其符合标准 JSON
            let jsonString = response.data;

            // 替换 Infinity（不区分大小写，可能有引号）
            // 匹配 : Infinity, : "Infinity", : Infinity, 等情况
            jsonString = jsonString.replace(
              /:\s*"?Infinity"?\s*([,}\]])/gi,
              ": null$1"
            );
            // 替换 -Infinity
            jsonString = jsonString.replace(
              /:\s*"?-Infinity"?\s*([,}\]])/gi,
              ": null$1"
            );
            // 替换 NaN
            jsonString = jsonString.replace(
              /:\s*"?NaN"?\s*([,}\]])/gi,
              ": null$1"
            );
            // 替换 undefined
            jsonString = jsonString.replace(
              /:\s*"?undefined"?\s*([,}\]])/gi,
              ": null$1"
            );

            // 解析 JSON 字符串
            const parsedData = JSON.parse(jsonString);
            // 关闭进度条动画
            NProgress.done();
            // 直接返回解析后的数据，跳过其他拦截器处理
            return parsedData;
          } catch (e) {
            console.error("解析 JSON 失败:", e);
            console.error("原始数据:", response.data);
            NProgress.done();
            return Promise.reject(new Error("解析响应数据失败"));
          }
        }

        // 如果 response.data 是字符串但不是 metadata 接口，尝试解析
        if (typeof response.data === "string") {
          try {
            // 同样处理特殊值
            let jsonString = response.data;
            jsonString = jsonString.replace(
              /:\s*"?Infinity"?\s*([,}\]])/gi,
              ": null$1"
            );
            jsonString = jsonString.replace(
              /:\s*"?-Infinity"?\s*([,}\]])/gi,
              ": null$1"
            );
            jsonString = jsonString.replace(
              /:\s*"?NaN"?\s*([,}\]])/gi,
              ": null$1"
            );
            jsonString = jsonString.replace(
              /:\s*"?undefined"?\s*([,}\]])/gi,
              ": null$1"
            );
            response.data = JSON.parse(jsonString);
          } catch (e) {
            // 如果解析失败，保持原样
            console.warn("响应数据解析失败，保持原样:", e);
          }
        }

        // 处理业务代码401
        if (response.data.code === 2401 || response.data.code === 401) {
          // debugger;
          ElNotification({
            title: "错误",
            message: response.data.message || "请先登录",
            type: "error",
            position: "bottom-right",
          });
          // 清除所有token
          removeToken();
          localStorage.removeItem("token175");
          localStorage.removeItem("token43");
          router.push("/login");
          return Promise.reject(response.data);
        }
        if (response.data.code === 2099) {
          ElNotification({
            title: "错误",
            message: response.data.message,
            type: "error",
            position: "bottom-right",
          });
          // removeToken();
          // router.push("/login");
          return Promise.reject(response.data);
        }
        // 处理所有非200状态码的情况
        // 支持两种响应格式：1. code字段 2. status字段
        const isSuccess =
          response.data.code === 200 ||
          response.data.code === 2000 ||
          response.data.code === 0 ||
          response.data.status === "success";

        if (!isSuccess) {
          // 不在这里显示通知，让业务代码自己处理错误信息
          // 直接 reject response.data，包含 code 和 message
          return Promise.reject(response.data);
        }

        const $config = response.config;
        // 关闭进度条动画
        NProgress.done();
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        return response.data;
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        // 关闭进度条动画
        NProgress.done();

        // 处理 HTTP 401 未授权错误
        if (error.response && error.response.status === 401) {
          const responseData = error.response.data;
          const errorMessage =
            (responseData && typeof responseData === "object" && responseData.message) ||
            "请先登录";
          
          ElNotification({
            title: "登录已过期",
            message: errorMessage,
            type: "error",
            position: "bottom-right",
          });
          
          // 清除所有token
          removeToken();
          localStorage.removeItem("token175");
          localStorage.removeItem("token43");
          
          // 跳转到登录页
          router.push("/login");
          
          return Promise.reject({
            code: 401,
            message: errorMessage,
            data: responseData?.data || [],
          });
        }

        // 处理 HTTP 错误响应，提取详细的错误信息
        if (error.response) {
          const responseData = error.response.data;
          // 如果响应数据包含 code 和 message，创建一个包含这些信息的错误对象
          if (responseData && typeof responseData === "object") {
            const data = responseData as any;
            // 处理业务代码401
            if (data.code === 401 || data.code === 2401) {
              ElNotification({
                title: "登录已过期",
                message: data.message || "请先登录",
                type: "error",
                position: "bottom-right",
              });
              // 清除所有token
              removeToken();
              localStorage.removeItem("token175");
              localStorage.removeItem("token43");
              router.push("/login");
              return Promise.reject(data);
            }
            if (data.message) {
              // 创建一个新的错误对象，包含详细的错误信息
              const errorWithMessage = {
                ...data,
                message: data.message,
                code: data.code,
                data: data.data,
              };
              return Promise.reject(errorWithMessage);
            }
          }
        }

        // 所有的响应异常 区分来源为取消请求/非取消请求
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig,
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch((error) => {
          reject(error);
        });
    });
  }

  /** 单独抽离的post工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("post", url, params, config);
  }

  /** 单独抽离的get工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<T>,
    config?: PureHttpRequestConfig
  ): Promise<P> {
    return this.request<P>("get", url, params, config);
  }
}

export const http = new PureHttp();
